<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>录制视频播放并下载</title>
    <style>
        video {
            height: 232px;
            margin: 0 12px 20px 0;
            vertical-align: top;
            width: calc(20em - 10px);
            background: #ccc;
        }
    </style>
</head>

<body>

    <video id="preview" autoplay muted></video>
    <video id="recorded" autoplay loop></video>

    <div>
        <button id="opencamera">Open camera</button>
        <button id="closecamera" disabled>Close camera</button>
        <br />
        <button id="record" disabled>Start Recording</button>
        <button id="stoprecord" disabled>Stop Recording</button>
        <br />
        <button id="play" disabled>Play</button>
        <button id="download" disabled>Download</button>
    </div>

    <script>
        const getUserMediaPromise = options => new Promise((resolve, reject) => {
            const nvgt = window.navigator;
            if (nvgt) {
                if (nvgt.mediaDevices && nvgt.mediaDevices.getUserMedia) {
                    return nvgt.mediaDevices.getUserMedia(options).then(resolve, reject);
                }
                const getUserMedia = nvgt.getUserMedia || nvgt.webkitGetUserMedia || nvgt.mozGetUserMedia;
                if (getUserMedia) {
                    return getUserMedia(options, resolve, reject)
                }
            }
            reject('当前环境不支持获取媒体设备。');
        });

        const video = document.querySelector('#preview');

        let cameraStream;
        const opencameraBtn = document.querySelector('#opencamera');
        const closecameraBtn = document.querySelector('#closecamera');
        const recordBtn = document.querySelector('#record');
        const stopRecordBtn = document.querySelector('#stoprecord');
        const playBtn = document.querySelector('#play');
        const downloadBtn = document.querySelector('#download');

        opencameraBtn.onclick = () => getUserMediaPromise({
            audio: true,
            video: true
        }).then(
            stream => {
                cameraStream = video.srcObject = stream;
                opencameraBtn.disabled = true;
                closecameraBtn.disabled = false;
                recordBtn.disabled = false;
            },
            err => {
                console.log('getUserMedia error: [' + err.name + '] ' + err.message)
            }
        );

        closecameraBtn.onclick = () => {
            cameraStream && cameraStream.getTracks()[0].stop();
            cameraStream = null;
            opencameraBtn.disabled = false;
            closecameraBtn.disabled = true;
            stopRecordBtn.onclick();
        };

        let mediaRecorder;
        let recordedBlobs;
        const mimeType = ['video/webm;codecs=vp9', 'video/webm;codecs=vp8', 'video/webm', ''].find(type => {
            return MediaRecorder.isTypeSupported(type);
        });
        // console.log('mimeType', mimeType);
        recordBtn.onclick = () => {
            recordedBlobs = [];
            try {
                mediaRecorder = new MediaRecorder(cameraStream, { mimeType });
            } catch (e) {
                alert('Exception while creating MediaRecorder: ' + e + '. mimeType: ' + mimeType);
                return;
            }
            recordBtn.disabled = true;
            stopRecordBtn.disabled = false;
            playBtn.disabled = true;
            downloadBtn.disabled = true;
            mediaRecorder.onstop = evt => {
                console.log('Recorder stopped');
            };
            mediaRecorder.ondataavailable = function (event) {
                if (event.data && event.data.size > 0) {
                    recordedBlobs.push(event.data);
                }
            };
            mediaRecorder.start(20); // 单次收集数据毫秒时长，ondataavailable 触发频率时长间隔
        };


        const recordedVideo = document.querySelector('#recorded');
        stopRecordBtn.onclick = () => {
            mediaRecorder && mediaRecorder.stop();
            mediaRecorder = null;
            // console.log('Recorded Blobs: ', recordedBlobs);
            recordedVideo.controls = true;
            playBtn.disabled = false;
            downloadBtn.disabled = false;
            stopRecordBtn.disabled = true;
            if (!cameraStream) {
                recordBtn.disabled = true;
            }
        };

        const getRecordedBlobUrl = () => {
            const superBuffer = new Blob(recordedBlobs, { type: mimeType.split(';')[0] });
            return window.URL.createObjectURL(superBuffer);
        };

        playBtn.onclick = () => {
            recordedVideo.src = getRecordedBlobUrl();
        }

        downloadBtn.onclick = () => {
            var a = document.createElement('a');
            a.style.display = 'none';
            a.href = getRecordedBlobUrl();
            a.download = 'test.webm';
            document.body.appendChild(a);
            a.click();
            setTimeout(function () {
                document.body.removeChild(a);
                window.URL.revokeObjectURL(url);
            }, 100);
        }


    </script>
</body>

</html>